"""
配置备份管理
提供配置备份的创建、恢复、管理功能
"""

import asyncio
import json
import logging
import hashlib
from datetime import datetime
from typing import Dict, List, Optional, Any
from data_models.Config import ConfigBackup


class ConfigBackupManager:
    """配置备份管理器"""

    def __init__(self, db_manager):
        self.db_manager = db_manager
        self.logger = logging.getLogger(__name__)

    async def create_backup(self, backup_name: str, configs: Dict[str, Any],
                           created_by: str = "system", description: str = None,
                           version: str = "1.0") -> int:
        """
        创建配置备份

        Args:
            backup_name: 备份名称
            configs: 配置数据字典 {key: value}
            created_by: 创建人
            description: 备份描述
            version: 备份版本

        Returns:
            int: 备份ID
        """
        try:
            # 构建备份数据
            backup_data = {
                'timestamp': datetime.now().isoformat(),
                'configs': {},
                'metadata': {
                    'total_configs': len(configs),
                    'backup_version': version,
                    'created_by': created_by,
                    'description': description
                }
            }

            # 添加配置项数据
            for key, value in configs.items():
                backup_data['configs'][key] = {
                    'value': str(value) if value is not None else None,
                    'backup_timestamp': datetime.now().isoformat()
                }

            # 计算数据校验和
            data_str = json.dumps(backup_data, sort_keys=True, ensure_ascii=False)
            checksum = hashlib.sha256(data_str.encode('utf-8')).hexdigest()
            file_size = len(data_str.encode('utf-8'))

            # 保存到数据库
            query = """
                INSERT INTO config_backups (
                    backup_name, backup_description, backup_data, backup_version,
                    is_auto_backup, created_by, file_size, checksum
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
            """
            backup_id = await self.db_manager.execute_insert(query, (
                backup_name,
                description,
                json.dumps(backup_data, ensure_ascii=False),
                version,
                False,  # 不是自动备份
                created_by,
                file_size,
                checksum
            ))

            self.logger.info(f"Created config backup: {backup_name} (ID: {backup_id})")
            return backup_id

        except Exception as e:
            self.logger.error(f"Failed to create config backup: {e}")
            raise

    async def create_auto_backup(self, configs: Dict[str, Any], reason: str = None) -> int:
        """
        创建自动备份

        Args:
            configs: 配置数据
            reason: 备份原因

        Returns:
            int: 备份ID
        """
        try:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            backup_name = f"auto_backup_{timestamp}"

            description = f"Automatic backup"
            if reason:
                description += f" - {reason}"

            return await self.create_backup(
                backup_name=backup_name,
                configs=configs,
                created_by="system",
                description=description,
                version="1.0"
            )

        except Exception as e:
            self.logger.error(f"Failed to create auto backup: {e}")
            raise

    async def get_backup(self, backup_id: int) -> Optional[Dict]:
        """
        获取配置备份

        Args:
            backup_id: 备份ID

        Returns:
            Optional[Dict]: 备份数据
        """
        try:
            query = "SELECT * FROM config_backups WHERE id = %s"
            result = await self.db_manager.execute_query_one(query, (backup_id,))
            return result

        except Exception as e:
            self.logger.error(f"Failed to get backup {backup_id}: {e}")
            return None

    async def get_backup_by_name(self, backup_name: str) -> Optional[Dict]:
        """
        根据名称获取配置备份

        Args:
            backup_name: 备份名称

        Returns:
            Optional[Dict]: 备份数据
        """
        try:
            query = "SELECT * FROM config_backups WHERE backup_name = %s"
            result = await self.db_manager.execute_query_one(query, (backup_name,))
            return result

        except Exception as e:
            self.logger.error(f"Failed to get backup by name {backup_name}: {e}")
            return None

    async def list_backups(self, limit: int = 50, offset: int = 0,
                          include_auto: bool = True) -> List[Dict]:
        """
        列出配置备份

        Args:
            limit: 限制数量
            offset: 偏移量
            include_auto: 是否包含自动备份

        Returns:
            List[Dict]: 备份列表
        """
        try:
            where_clause = ""
            params = []

            if not include_auto:
                where_clause = "WHERE is_auto_backup = FALSE"

            query = f"""
                SELECT id, backup_name, backup_description, created_by,
                       created_at, file_size, is_auto_backup, backup_version
                FROM config_backups
                {where_clause}
                ORDER BY created_at DESC
                LIMIT %s OFFSET %s
            """
            params.extend([limit, offset])

            return await self.db_manager.execute_query(query, tuple(params))

        except Exception as e:
            self.logger.error(f"Failed to list backups: {e}")
            return []

    async def list_backups_count(self, include_auto: bool = True) -> int:
        """
        获取备份总数

        Args:
            include_auto: 是否包含自动备份

        Returns:
            int: 备份总数
        """
        try:
            where_clause = ""
            params = []

            if not include_auto:
                where_clause = "WHERE is_auto_backup = FALSE"

            query = f"SELECT COUNT(*) as count FROM config_backups {where_clause}"
            result = await self.db_manager.execute_query_one(query, tuple(params))
            return result['count'] if result else 0

        except Exception as e:
            self.logger.error(f"Failed to get backups count: {e}")
            return 0

    async def restore_backup(self, backup_id: int, configs: Dict[str, Any],
                           created_by: str = "system") -> bool:
        """
        恢复配置备份

        Args:
            backup_id: 备份ID
            configs: 当前配置字典
            created_by: 操作人

        Returns:
            bool: 恢复是否成功
        """
        try:
            # 获取备份数据
            backup = await self.get_backup(backup_id)
            if not backup:
                self.logger.error(f"Backup not found: {backup_id}")
                return False

            backup_data = json.loads(backup['backup_data'])
            backup_configs = backup_data.get('configs', {})

            # 验证备份数据完整性
            if not await self._verify_backup_integrity(backup):
                self.logger.error(f"Backup integrity check failed: {backup_id}")
                return False

            # 记录恢复前的当前配置
            await self._create_restore_snapshot(configs, backup_id, created_by)

            # 恢复配置
            restore_count = 0
            errors = []

            for key, config_info in backup_configs.items():
                try:
                    value = config_info.get('value')
                    if value is not None:
                        # 这里应该调用配置管理器更新配置
                        # 为了解耦，我们返回需要更新的配置
                        restore_count += 1
                except Exception as e:
                    errors.append(f"Failed to restore {key}: {e}")

            if errors:
                self.logger.error(f"Restore completed with {len(errors)} errors: {errors}")
            else:
                self.logger.info(f"Successfully restored {restore_count} configurations from backup {backup_id}")

            return len(errors) == 0

        except Exception as e:
            self.logger.error(f"Failed to restore backup {backup_id}: {e}")
            return False

    async def get_restore_plan(self, backup_id: int, current_configs: Dict[str, Any]) -> Dict[str, Any]:
        """
        获取恢复计划，展示将要恢复的配置变更

        Args:
            backup_id: 备份ID
            current_configs: 当前配置

        Returns:
            Dict[str, Any]: 恢复计划
        """
        try:
            backup = await self.get_backup(backup_id)
            if not backup:
                return {'error': 'Backup not found'}

            backup_data = json.loads(backup['backup_data'])
            backup_configs = backup_data.get('configs', {})

            plan = {
                'backup_id': backup_id,
                'backup_name': backup['backup_name'],
                'backup_date': backup['created_at'],
                'changes': {},
                'summary': {
                    'total_changes': 0,
                    'new_configs': 0,
                    'updated_configs': 0,
                    'removed_configs': 0
                }
            }

            # 分析配置变更
            all_keys = set(current_configs.keys()) | set(backup_configs.keys())

            for key in all_keys:
                current_value = current_configs.get(key)
                backup_value = backup_configs.get(key, {}).get('value')

                if backup_value is None:
                    # 备份中没有这个配置
                    plan['changes'][key] = {
                        'action': 'remove',
                        'old_value': str(current_value) if current_value is not None else None,
                        'new_value': None
                    }
                    plan['summary']['removed_configs'] += 1

                elif current_value != backup_value:
                    # 配置值变更
                    plan['changes'][key] = {
                        'action': 'update',
                        'old_value': str(current_value) if current_value is not None else None,
                        'new_value': backup_value
                    }
                    plan['summary']['updated_configs'] += 1

                elif key not in current_configs:
                    # 新增配置
                    plan['changes'][key] = {
                        'action': 'create',
                        'old_value': None,
                        'new_value': backup_value
                    }
                    plan['summary']['new_configs'] += 1

            plan['summary']['total_changes'] = (
                plan['summary']['new_configs'] +
                plan['summary']['updated_configs'] +
                plan['summary']['removed_configs']
            )

            return plan

        except Exception as e:
            self.logger.error(f"Failed to get restore plan for backup {backup_id}: {e}")
            return {'error': str(e)}

    async def delete_backup(self, backup_id: int) -> bool:
        """
        删除配置备份

        Args:
            backup_id: 备份ID

        Returns:
            bool: 删除是否成功
        """
        try:
            query = "DELETE FROM config_backups WHERE id = %s"
            success = await self.db_manager.execute_update(query, (backup_id,)) > 0

            if success:
                self.logger.info(f"Deleted backup: {backup_id}")
            else:
                self.logger.warning(f"Backup not found for deletion: {backup_id}")

            return success

        except Exception as e:
            self.logger.error(f"Failed to delete backup {backup_id}: {e}")
            return False

    async def cleanup_old_backups(self, days: int = 30, keep_count: int = 10) -> int:
        """
        清理旧备份

        Args:
            days: 保留天数
            keep_count: 最少保留数量

        Returns:
            int: 清理的备份数量
        """
        try:
            # 获取总备份数
            total_count = await self.list_backups_count()

            if total_count <= keep_count:
                self.logger.info(f"Only {total_count} backups found, keeping all")
                return 0

            # 获取超过保留天数的备份
            query = """
                SELECT id, backup_name, created_at
                FROM config_backups
                WHERE created_at < DATE_SUB(NOW(), INTERVAL %s DAY)
                ORDER BY created_at ASC
            """
            old_backups = await self.db_manager.execute_query(query, (days,))

            # 保留最新的几个备份
            if len(old_backups) > keep_count:
                backups_to_delete = old_backups[:-keep_count]
            else:
                backups_to_delete = []

            deleted_count = 0
            for backup in backups_to_delete:
                if await self.delete_backup(backup['id']):
                    deleted_count += 1
                    self.logger.info(f"Deleted old backup: {backup['backup_name']}")

            self.logger.info(f"Cleaned up {deleted_count} old backups")
            return deleted_count

        except Exception as e:
            self.logger.error(f"Failed to cleanup old backups: {e}")
            return 0

    async def export_backup(self, backup_id: int, format: str = 'json') -> str:
        """
        导出备份数据

        Args:
            backup_id: 备份ID
            format: 导出格式（json/yaml/toml）

        Returns:
            str: 导出的数据
        """
        try:
            backup = await self.get_backup(backup_id)
            if not backup:
                return ""

            backup_data = json.loads(backup['backup_data'])

            if format.lower() == 'json':
                return json.dumps(backup_data, indent=2, ensure_ascii=False)
            elif format.lower() == 'yaml':
                try:
                    import yaml
                    return yaml.dump(backup_data, default_flow_style=False, allow_unicode=True)
                except ImportError:
                    self.logger.warning("PyYAML not installed, falling back to JSON")
                    return json.dumps(backup_data, indent=2, ensure_ascii=False)
            else:
                self.logger.warning(f"Unsupported export format: {format}, using JSON")
                return json.dumps(backup_data, indent=2, ensure_ascii=False)

        except Exception as e:
            self.logger.error(f"Failed to export backup {backup_id}: {e}")
            return ""

    async def import_backup(self, backup_data: str, format: str = 'json',
                           backup_name: str = None, created_by: str = "system") -> int:
        """
        导入备份数据

        Args:
            backup_data: 备份数据字符串
            format: 数据格式（json/yaml）
            backup_name: 备份名称
            created_by: 创建人

        Returns:
            int: 导入的备份ID
        """
        try:
            # 解析备份数据
            if format.lower() == 'json':
                data = json.loads(backup_data)
            elif format.lower() == 'yaml':
                try:
                    import yaml
                    data = yaml.safe_load(backup_data)
                except ImportError:
                    raise ImportError("PyYAML is required for YAML import")
            else:
                raise ValueError(f"Unsupported format: {format}")

            # 验证数据格式
            if not isinstance(data, dict) or 'configs' not in data:
                raise ValueError("Invalid backup data format")

            # 生成备份名称
            if not backup_name:
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                backup_name = f"imported_backup_{timestamp}"

            # 提取配置数据
            configs = {}
            for key, config_info in data.get('configs', {}).items():
                if isinstance(config_info, dict):
                    configs[key] = config_info.get('value')
                else:
                    configs[key] = config_info

            # 创建备份记录
            return await self.create_backup(
                backup_name=backup_name,
                configs=configs,
                created_by=created_by,
                description=f"Imported from {format.upper()} file",
                version=data.get('metadata', {}).get('backup_version', '1.0')
            )

        except Exception as e:
            self.logger.error(f"Failed to import backup: {e}")
            raise

    async def _verify_backup_integrity(self, backup: Dict) -> bool:
        """验证备份完整性"""
        try:
            stored_checksum = backup['checksum']
            backup_data = backup['backup_data']

            # 重新计算校验和
            computed_checksum = hashlib.sha256(
                backup_data.encode('utf-8')
            ).hexdigest()

            return stored_checksum == computed_checksum

        except Exception as e:
            self.logger.error(f"Backup integrity verification failed: {e}")
            return False

    async def _create_restore_snapshot(self, current_configs: Dict[str, Any],
                                     backup_id: int, created_by: str) -> int:
        """创建恢复前的快照"""
        try:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            snapshot_name = f"pre_restore_snapshot_{timestamp}_for_backup_{backup_id}"

            return await self.create_backup(
                backup_name=snapshot_name,
                configs=current_configs,
                created_by=created_by,
                description=f"Pre-restore snapshot before restoring from backup {backup_id}",
                version="1.0"
            )

        except Exception as e:
            self.logger.error(f"Failed to create restore snapshot: {e}")
            return 0

    async def get_backup_statistics(self) -> Dict[str, Any]:
        """
        获取备份统计信息

        Returns:
            Dict[str, Any]: 统计信息
        """
        try:
            stats = {}

            # 总备份数
            total_query = "SELECT COUNT(*) as count FROM config_backups"
            total_result = await self.db_manager.execute_query_one(total_query)
            stats['total_backups'] = total_result['count'] if total_result else 0

            # 自动备份数
            auto_query = "SELECT COUNT(*) as count FROM config_backups WHERE is_auto_backup = TRUE"
            auto_result = await self.db_manager.execute_query_one(auto_query)
            stats['auto_backups'] = auto_result['count'] if auto_result else 0

            # 手动备份数
            stats['manual_backups'] = stats['total_backups'] - stats['auto_backups']

            # 总存储大小
            size_query = "SELECT SUM(file_size) as total_size FROM config_backups"
            size_result = await self.db_manager.execute_query_one(size_query)
            stats['total_size_bytes'] = size_result['total_size'] if size_result['total_size'] else 0

            # 最新备份时间
            latest_query = "SELECT MAX(created_at) as latest FROM config_backups"
            latest_result = await self.db_manager.execute_query_one(latest_query)
            stats['latest_backup'] = latest_result['latest'] if latest_result['latest'] else None

            return stats

        except Exception as e:
            self.logger.error(f"Failed to get backup statistics: {e}")
            return {}